package com.example.personalizededucationsystem.service;

import com.example.personalizededucationsystem.dto.request.KnowledgePointRequest;
import com.example.personalizededucationsystem.dto.request.QuestionRequest;
import com.example.personalizededucationsystem.exception.DuplicateNameException;
import com.example.personalizededucationsystem.model.KnowledgePoint;
import com.example.personalizededucationsystem.model.Question;
import com.example.personalizededucationsystem.model.User;
import com.example.personalizededucationsystem.repository.KnowledgePointRepository;
import com.example.personalizededucationsystem.repository.QuestionRepository;
import com.example.personalizededucationsystem.service.recommendation.RecommendationStrategy;
import com.example.personalizededucationsystem.service.recommendation.RecommendationStrategyFactory;
import com.example.personalizededucationsystem.utils.ApprovalStatus;
import com.example.personalizededucationsystem.utils.PagedResult;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class QuestionBankService {

    private static final int COUNT = 5;
    private static final int PAGE_SIZE = 10;
    private final QuestionRepository questionRepository;
    private final KnowledgePointRepository knowledgePointRepository;
    private final RecommendationStrategyFactory strategyFactory;

    @Autowired
    public QuestionBankService(QuestionRepository questionRepository, KnowledgePointRepository knowledgePointRepository, RecommendationStrategyFactory strategyFactory) {
        this.questionRepository = questionRepository;
        this.knowledgePointRepository = knowledgePointRepository;
        this.strategyFactory = strategyFactory;
    }

    @Transactional
    public KnowledgePoint createKnowledgePoint(KnowledgePointRequest request) {
        Optional<KnowledgePoint> existing = knowledgePointRepository.findByName(request.getName());
        if (existing.isPresent()) {
            throw new DuplicateNameException("名称重复，已存在该知识点");
        }
        KnowledgePoint kp = new KnowledgePoint();
        kp.setName(request.getName());
        kp.setSubject(request.getSubject());
        if (!request.getDescription().isEmpty()) {
            kp.setDescription(request.getDescription());
        } else {
            kp.setDescription("无描述");
        }
        return knowledgePointRepository.save(kp);
    }

    @Transactional
    public Question createQuestion(QuestionRequest request, User creator) {
        Question question = new Question();
        question.setContent(request.getContent());
        question.setType(request.getType());
        question.setOptions(request.getOptions());
        question.setAnswer(request.getAnswer());
        question.setAnalysis(request.getAnalysis());
        question.setDifficulty(request.getDifficulty());
        question.setCreator(creator);
        question.setStatus(ApprovalStatus.PENDING);

        if (request.getKnowledgePointNames() != null && !request.getKnowledgePointNames().isEmpty()) {
            List<KnowledgePoint> kps = request.getKnowledgePointNames().stream()
                    .map(knowledgePointRepository::findByName)
                    .flatMap(Optional::stream)
                    .toList();
            question.setKnowledgePoints(new HashSet<>(kps));
        }
        return questionRepository.save(question);
    }

    public List<Question> getPersonalizedPracticeQuestions(User student, String subject) {
        RecommendationStrategy weakestPointStrategy = strategyFactory.getStrategy("WEAKEST_POINT");
        List<Question> recommendedQuestions = new ArrayList<>(weakestPointStrategy.recommend(student, subject, 1));

        if (recommendedQuestions.size() < COUNT) {
            int remainingCount = COUNT - recommendedQuestions.size();
            RecommendationStrategy fallbackStrategy = strategyFactory.getStrategy("RANDOM");
            List<Question> fallbackQuestions = fallbackStrategy.recommend(student, subject, remainingCount);
            recommendedQuestions.addAll(fallbackQuestions);
        }

        return recommendedQuestions.stream().limit(COUNT).collect(Collectors.toList());
    }

    public PagedResult<Question> getApprovedQuestions(int page, String keyword, String subject) {
        Pageable pageable = PageRequest.of(page - 1, PAGE_SIZE, Sort.by("questionId").descending());
        Page<Question> questionPage = questionRepository.findQuestionsByStatusKeywordAndSubject(ApprovalStatus.APPROVED, keyword, subject, pageable);
        return new PagedResult<>(questionPage.getContent(), questionPage.getTotalElements());
    }

    public PagedResult<Question> getPendingQuestions(int page, String keyword, String subject) {
        Pageable pageable = PageRequest.of(page - 1, PAGE_SIZE, Sort.by("questionId").descending());
        Page<Question> pageResult = questionRepository.findQuestionsByStatusKeywordAndSubject(ApprovalStatus.PENDING, keyword, subject, pageable);
        return new PagedResult<>(pageResult.getContent(), pageResult.getTotalElements());
    }

    public Question getAccurateQuestion(Long id) {
        Optional<Question> question = questionRepository.findById(id);
        if (question.isPresent()) {
            return question.get();
        } else throw new EntityNotFoundException();
    }

    public boolean approveQuestion(Long id) {
        return updateStatus(id, ApprovalStatus.APPROVED);
    }

    public boolean rejectQuestion(Long id) {
        return updateStatus(id, ApprovalStatus.REJECTED);
    }

    private boolean updateStatus(Long id, ApprovalStatus status) {
        Optional<Question> optional = questionRepository.findById(id);
        if (optional.isEmpty()) return false;

        Question question = optional.get();
        question.setStatus(status);
        questionRepository.save(question);
        return true;
    }
}